package com.icehand.axon.demo.command.aggregates;

import com.icehand.axon.demo.command.commands.CreateAccountCommand;
import com.icehand.axon.demo.command.commands.WithdrawMoneyCommand;
import com.icehand.axon.demo.common.domain.AccountId;
import com.icehand.axon.demo.common.events.AccountCreatedEvent;
import com.icehand.axon.demo.common.events.MoneyWithdrawnEvent;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.axonframework.commandhandling.CommandHandler;
import org.axonframework.commandhandling.model.AggregateIdentifier;
import org.axonframework.eventhandling.EventHandler;
import org.axonframework.spring.stereotype.Aggregate;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import java.math.BigDecimal;

import static org.axonframework.commandhandling.model.AggregateLifecycle.apply;

/**
 * @author icehand
 */
@Slf4j
@Entity
@NoArgsConstructor
@Aggregate
public class BankAccount {
    @AggregateIdentifier
    private AccountId accountId;
    @Column
    private String accountName;
    @Column
    private BigDecimal balance;

    @CommandHandler
    public BankAccount(CreateAccountCommand command) {
        log.debug("Construct a new BankAccount");
        apply(new AccountCreatedEvent(command.getAccountId(),command.getAccountName(),command.getAmount()));
    }

    @CommandHandler
    public void handle(WithdrawMoneyCommand command) {
        log.debug("handle BankAccount");
        apply(new MoneyWithdrawnEvent(command.getAccountId(),command.getAmount()));
    }

    @EventHandler
    public void on(AccountCreatedEvent event) {
        this.accountId = event.getAccountId();
        this.accountName = event.getAccountName();
        this.balance = event.getAmount();
        log.info("Account {} is create with balance {}",accountId,balance);
    }

    @EventHandler
    public void on(MoneyWithdrawnEvent event) {
        BigDecimal result = balance.subtract(event.getAmount());
        if(result.compareTo(BigDecimal.ZERO) < 0){
            log.error("cannot withdraw more money than the balance");
        } else {
            this.balance = result;
            log.info("withdraw {} from account {},balance result: {}",event.getAmount(),event.getAccountId(),result);
        }
    }

    @Id
    public String getAccountId(){
        return accountId.toString();
    }

    public void setAccountId(String accountId){
        this.accountId = new AccountId(accountId);
    }

    public String getAccountName() {
        return accountName;
    }

    public void setAccountName(String accountName) {
        this.accountName = accountName;
    }

    public BigDecimal getBalance() {
        return balance;
    }

    public void setBalance(BigDecimal balance) {
        this.balance = balance;
    }
}
